{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from bqplot import Graph, LinearScale, ColorScale, Figure, Tooltip\n",
    "from ipywidgets import Layout"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nodes and Links should be supplied to the Graph mark. \n",
    "<p>Node attributes\n",
    "\n",
    "| Attribute|      Type     |  Description | Default |\n",
    "|:----------:|:-------------:|:------:|\n",
    "| label |  str | node label | mandatory attribute |\n",
    "| label_display |  {center, outside, none} | label display options | center |\n",
    "| shape |  {circle, ellipse, rect} | node shape | circle |\n",
    "| shape_attrs |  dict | [node SVG attributes](https://www.w3.org/TR/SVG/shapes.html) | {'r': 15} |\n",
    "<p> Link Attributes\n",
    "\n",
    "| Attribute|      Type     |  Description | Default |\n",
    "|:----------:|:-------------:|:------:|\n",
    "| source |  int | source node index | mandatory attribute |\n",
    "| target |  int | target node index | mandatory attribute |\n",
    "| value |  float | value of the link. Use np.nan if you do not want a link| - |\n",
    "\n",
    "<p> Link data can also be supplied using a link_matrix which is a numpy array of shape (n, n) where n is the number of nodes in the graph\n",
    "\n",
    "<p> Link Data can be passed in through 3 data attributes - \n",
    "1. link_data - list of dicts (e.g. [{'source': 0, 'target': 1, 'value': 10}, {'source': 2, 'target': 1, 'value': 20},...]\n",
    "2. link_matrix - 2-d numpy array of shape (n, n) where n is the number of nodes\n",
    "3. link_color - 2-d numpy array of shape (n, n) where n is the number of nodes. This attribute can be used to encode the link_color by passing in a link_color scale\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig_layout = Layout(width='960px', height='500px')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Directed Graph\n",
    "If we dont specify the x and y location for nodes then the force layout will set the location of nodes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_data = list('ABCDEFG')\n",
    "link_data = [{'source': s, 'target': t} for s, t in np.random.randint(0, 7, (10, 2))]\n",
    "graph = Graph(node_data=node_data, link_data=link_data, charge=-600, colors=['orange'] * 7)\n",
    "Figure(marks=[graph], layout=fig_layout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Explicitly setting x and y location for nodes using x and y scales. \n",
    "Force layout animation is disabled in this case"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_data = list('ABCDEFG')\n",
    "\n",
    "#using link matrix to set links\n",
    "link_matrix = np.zeros((7, 7))\n",
    "xs = LinearScale()\n",
    "ys = LinearScale()\n",
    "x = [100, 200, 200, 300, 300, 300, 300]\n",
    "y = [2, .5, 4, 8, 6, 4, 1]\n",
    "graph = Graph(node_data=node_data, link_matrix=link_matrix, link_type='line', \n",
    "              colors=['orange'] * 7,\n",
    "              scales={'x': xs, 'y': ys, }, x=x, y=y, \n",
    "              directed=False)\n",
    "Figure(marks=[graph], layout=fig_layout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Color code nodes using 'color' data attribute"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_data = list('ABCDEFG')\n",
    "\n",
    "#using link matrix to set links\n",
    "link_matrix = np.zeros((7, 7))\n",
    "xs = LinearScale(min=0, max=500)\n",
    "ys = LinearScale(min=0, max=10)\n",
    "cs = ColorScale(scheme='Reds')\n",
    "x = [100, 200, 200, 300, 300, 300, 300]\n",
    "y = [2, .5, 4, 8, 6, 4, 1]\n",
    "graph = Graph(node_data=node_data, link_matrix=link_matrix, link_type='line', \n",
    "              color=np.random.rand(7),\n",
    "              scales={'x': xs, 'y': ys, 'color': cs}, x=x, y=y, \n",
    "              directed=False)\n",
    "Figure(marks=[graph], layout=fig_layout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Color code links using link_color scale"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_data = list('ABCDEFG')\n",
    "\n",
    "link_data = [{'source': s, 'target': t, 'value': np.random.rand()} for s, t in np.random.randint(0, 7, (20, 2))]\n",
    "\n",
    "xs = LinearScale()\n",
    "ys = LinearScale()\n",
    "lcs = ColorScale(scheme='Greens')\n",
    "x = [100, 200, 200, 300, 300, 300, 300]\n",
    "y = [2, .5, 4, 8, 6, 4, 1]\n",
    "graph = Graph(node_data=node_data, link_data=link_data, link_type='line',\n",
    "              colors=['orange'], directed=False, \n",
    "              scales={'x': xs, 'y': ys, 'link_color': lcs}, \n",
    "              x=x, y=y, color=np.random.rand(7))\n",
    "Figure(marks=[graph], layout=fig_layout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Custom node attributes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "node_data = [\n",
    "    {'label': 'A', 'shape': 'circle', 'shape_attrs': {'r': 20}, 'foo': 1},\n",
    "    {'label': 'Node B', 'shape': 'rect', 'shape_attrs': {'rx': 10, 'ry': 10, 'width': 40}, 'foo': 2},\n",
    "    {'label': 'C', 'shape': 'ellipse', 'foo': 4},\n",
    "    {'label': 'D', 'shape': 'rect', 'shape_attrs': {'width': 30, 'height': 30}, 'foo': 100},\n",
    "]\n",
    "\n",
    "link_data = [{'source': s, 'target': t, 'value': np.random.rand()} for s, t in np.random.randint(0, 4, (8, 2))]\n",
    "\n",
    "graph = Graph(node_data=node_data, link_data=link_data, link_distance=150)\n",
    "Figure(marks=[graph], layout=fig_layout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Add tooltips on nodes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tooltip = Tooltip(fields=['label', 'foo'], formats=['', '', ''])\n",
    "graph.tooltip = tooltip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Add a line chart as a tooltip"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import bqplot.pyplot as plt\n",
    "plt.clear()\n",
    "line = plt.plot(np.cumsum(np.random.randn(20)))\n",
    "# hover on nodes to see the plot\n",
    "graph.tooltip = plt.current_figure()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Custom styling of hovered and selected nodes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "graph.hovered_style = {'stroke': 'red'}\n",
    "graph.unhovered_style = {'opacity': '0.4'}\n",
    "\n",
    "graph.selected_style = {'opacity': '1', 'stroke': 'white', 'stroke-width': '2.5'}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# click on any node to select it (selected attribute gets populated with the index of the selected node)\n",
    "graph.selected"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Add element click and background click handlers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_event(self, target):\n",
    "    print(target)\n",
    "\n",
    "graph.on_background_click(print_event)\n",
    "graph.on_element_click(print_event)"
   ]
  }
 ],
 "metadata": {
  "input_collapsed": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
